﻿using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using ChatTools;

namespace ChatService
{
    internal class Server
    {
        private Socket server_socket;
        private Dictionary<Socket, int> Clients;
        private object clientListLock = new object();
        private const int RECEIVE_BUFF_SIZE = 1024;

        public event EventHandler<RefreshClientsEventArgs> RefreshClients;

        public Server()
        {
            this.server_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            this.Clients = new Dictionary<Socket, int>();
        }

        public bool Start(string IP, int port)
        {
            this.server_socket.Bind((EndPoint)new IPEndPoint(IPAddress.Parse(IP), port));
            this.server_socket.Listen(10);
            this.server_socket.BeginAccept(new AsyncCallback(this.CallbackAccept), null);
            ThreadPool.QueueUserWorkItem(new WaitCallback(this.ThreadProcess_ClientDamon));
            return true;
        }

        private void ThreadProcess_ClientDamon(object state)
        {
            bool flag = false;

            while (true)
            {
                lock (this.clientListLock)
                {
                    for (int index = 0; index < this.Clients.Count; ++index)
                    {
                        if (!Tools.IsSocketConnectedServer(this.Clients.ElementAt(index).Key))
                        {
                            try
                            {
                                this.Clients.ElementAt(index).Key.Shutdown(SocketShutdown.Both);
                            }
                            finally
                            {
                                this.Clients.ElementAt(index).Key.Close();
                            }
                            this.Clients.Remove(this.Clients.ElementAt(index).Key);
                            flag = true;
                        }
                    }
                }
                if (flag)
                {
                    this.RefreshClientList();
                    flag = false;
                }
            }
        }

        private void CallbackAccept(IAsyncResult ar)
        {

            Socket socket = this.server_socket.EndAccept(ar);

            //获取消息的内容
            ReceiveState state = new ReceiveState(socket, RECEIVE_BUFF_SIZE);

            lock (this.clientListLock)
            {
                this.Clients.Add(socket, 0);
            }
            socket.BeginReceive(state.Buffer, 0, RECEIVE_BUFF_SIZE, SocketFlags.None, new AsyncCallback(this.ReceiveCallback), (object)state);
            //this.RefreshClientList();
            this.server_socket.BeginAccept(new AsyncCallback(this.CallbackAccept), null);
        }

        private void ReceiveCallback(IAsyncResult ar)
        {
            ReceiveState asyncState = ar.AsyncState as ReceiveState;
            int len;
            try
            {
                len = asyncState.Socket.EndReceive(ar);
            }
            catch (Exception ex) when (ex is ObjectDisposedException || ex is SocketException)
            {
                return;
            }
            this.ProcessReceivedData(asyncState.Socket, asyncState.Buffer, len);
            asyncState.Socket.BeginReceive(asyncState.Buffer, 0, RECEIVE_BUFF_SIZE, SocketFlags.None, new AsyncCallback(this.ReceiveCallback), (object)asyncState);
        }

        private void ProcessReceivedData(Socket socket, byte[] buffer, int len)
        {
            string str = Encoding.Default.GetString(buffer, 0, len);
            string[] strings = str.Split(new char[1] { '|' });
            int type = int.Parse(strings[0]);
            int sendid = int.Parse(strings[1]);
            if (type == 0)
            {
                if (this.Clients.ContainsKey(socket))
                {
                    this.Clients[socket] = sendid;
                }
                else
                {
                    this.Clients.Add(socket, sendid);
                }
                this.RefreshClientList();
            }
            else if (type == 1)
            {
                int receiveid = int.Parse(strings[2]);
                string msg = strings[3];
                foreach (Socket key in this.Clients.Keys)
                {
                    if (this.Clients[key] == receiveid)
                    {
                        string sendmsg = string.Format("{0}|{1}|{2}|{3}", 1, sendid, receiveid, msg);
                        byte[] buffer1 = Encoding.Default.GetBytes(sendmsg);
                        //byte[] bytes = Encoding.Default.GetBytes(string.Format("[{0}] ", socket.RemoteEndPoint.ToString()));
                        //byte[] buffer1 = new byte[bytes.Length + buffer.Length];
                        //bytes.CopyTo((Array)buffer1, 0);
                        //buffer.CopyTo((Array)buffer1, bytes.Length);
                        key.Send(buffer1, buffer1.Length, SocketFlags.None);
                    }
                }
            }

        }

        private void RefreshClientList()
        {
            List<string> source = new List<string>();
            lock (this.clientListLock)
            {
                foreach (Socket key in this.Clients.Keys)
                {
                    source.Add(key.RemoteEndPoint.ToString() + "-" + this.Clients[key]);
                }
            }
            this.RefreshClients((object)this, new RefreshClientsEventArgs()
            {
                Clients = source.ToArray<string>()
            });
        }
    }
}
